package com.woopsion.spring.contextSupport;

import com.woopsion.spring.beans.Autowired;
import com.woopsion.spring.beans.Scope;
import com.woopsion.spring.processor.BeanPostProcessor;
import com.woopsion.spring.processor.InitializingBean;
import com.woopsion.spring.stereotype.*;
import org.apache.commons.lang3.StringUtils;

import java.io.File;
import java.lang.reflect.Field;
import java.lang.reflect.InvocationTargetException;
import java.net.URL;
import java.util.ArrayList;
import java.util.Enumeration;
import java.util.List;
import java.util.concurrent.ConcurrentHashMap;

/**
 * @author woopsion
 * @date 2025-05-30
 * 基于注解读取的ioc容器bean加载方案
 */
@SuppressWarnings("all")
public class woopsionContextAnnotationIoc {
    private Class wpcScanConfigClass;

    /**
     * ioc 单例容器
     */
    private final ConcurrentHashMap<String , Object> singleBeanIoc = new ConcurrentHashMap<>();

    /**
     * BeanDefinition bean信息容器
     */
    private final ConcurrentHashMap<String , BeanDefinition> BeanDefinitionMap = new ConcurrentHashMap<>();

    /**
     * 后置处理器容器
     */
    private final List<BeanPostProcessor> beanPostProcessorList = 
            new ArrayList<>();
   
    
    
    public Object getBean(String name){
        if(BeanDefinitionMap.containsKey(name)) {
            BeanDefinition beanDefinition = BeanDefinitionMap.get(name);
            //得到bean的scope , 分别处理
            if("singleton".equalsIgnoreCase(beanDefinition.getScope())) {
                //单例，直接从 bean单例池获取
                return singleBeanIoc.get(name);
            } else { //不是单例，则没有返回新的实例
                return createBean(beanDefinition);
            }
        } else {
            throw new NullPointerException("没有该 bean");
        }
    }

    public woopsionContextAnnotationIoc(Class wpcScanConfigClass) throws ClassNotFoundException, InstantiationException, IllegalAccessException {
        this.wpcScanConfigClass = wpcScanConfigClass;
        beanDefinitionsByscan(wpcScanConfigClass);

//        System.out.println(BeanDefinitionMap);
        //通过 beanDefinitionMap , 初始化 singletonObjects bean 单列池
        Enumeration<String> keys = BeanDefinitionMap.keys();
        while (keys.hasMoreElements()) {
            //得到beanName
            String beanName = keys.nextElement();
            //通过beanName 得到 beanDefinition
            BeanDefinition beanDefinition = BeanDefinitionMap.get(beanName);
            if ("singleton".equalsIgnoreCase(beanDefinition.getScope())) {
                //将该bean实例放入 singletonObjects
                Object bean = createBean(beanDefinition);
                singleBeanIoc.put(beanName, bean);
            }
        }
        System.out.println("singletonObjects 单例池 = " + singleBeanIoc);
    }

    /**
     * 扫描要扫描的组件包，并且将bean封装成definition，加入BeanDefinitionMap容器中
     * @param configClass
     * @throws InstantiationException
     * @throws IllegalAccessException
     * @throws ClassNotFoundException
     */
    public void beanDefinitionsByscan(Class configClass) throws InstantiationException, IllegalAccessException, ClassNotFoundException {
        ComponentScanInfo declaredAnnotation = (ComponentScanInfo) this.
                wpcScanConfigClass.
                getDeclaredAnnotation
                        (ComponentScanInfo.class);

        /**
         * 将配置类注解ComponentScanInfo信息中，组件包所在地址转换成文件路径
         */
        String packgePath = declaredAnnotation.value();
        packgePath = packgePath.replace(".","/");
        System.out.println("packgePath= " + packgePath);


        ClassLoader classLoader = woopsionContextAnnotationIoc.class.getClassLoader();
        
        //获取绝对路径
        URL resource = classLoader.getResource(packgePath);
        System.out.println(resource);
        File files = new File(resource.getFile());


        if (files.isDirectory()){
            File[] files1 = files.listFiles();
            for (File f : files1 ){
                if (f.isDirectory()) continue;
                if(!f.getName().endsWith(".class"))continue;//不是class文件 就跳过
                System.out.println("f‘s realFilePath:" + f.getAbsolutePath());
                String absolutePath = f.getAbsolutePath();

                int start = absolutePath.lastIndexOf('\\');
                int end = absolutePath.indexOf(".class");
                String className = absolutePath.substring(start + 1 , end );

                packgePath = packgePath.replace('/','.');
                Class<?> aClass = Class.forName(packgePath +"."+ className);
                String classId = className;

                if(aClass.isAnnotationPresent(Component.class) ||
                        aClass.isAnnotationPresent(Controller.class) ||
                        aClass.isAnnotationPresent(Repository.class) ||
                        aClass.isAnnotationPresent(Service.class)
                ){
                    
                    if(aClass.isAnnotationPresent(Component.class)){

                        Component declaredAnnotation1 = aClass.getDeclaredAnnotation(Component.class);
                        classId = declaredAnnotation1.value();

                        if("".equals(classId)) {
                            classId = StringUtils.uncapitalize(className);//首字母小写类名作为beanId
                            
                        }

                        //2. 如果发现是一个后置处理器, 放入到 beanPostProcessorList
                        //3. 在原生的Spring容器中, 对后置处理器还是走的getBean, createBean
                        //   , 但是需要我们在singletonObjects 加入相应的业务逻辑
                        //4. 因为这里我们是为了讲解后置处理去的机制，我就简化
                        //5. 如果小伙伴们，仍然走以前的逻辑，也可以，就是要麻烦一点


                        //判断当前的这个clazz有没有实现BeanPostProcessor
                        //说明, 这里我们不能使用 instanceof 来判断clazz是否实现了BeanPostProcessor
                        //原因: clazz不是一个实例对象，而是一个类对象/clazz, 使用isAssignableFrom
                        //小伙伴将其当做一个语法理解
                        if (BeanPostProcessor.class.isAssignableFrom(aClass)) {

                            BeanPostProcessor beanPostProcessor =
                                    (BeanPostProcessor) aClass.newInstance();
                            //放入到beanPostProcessorList
                            beanPostProcessorList.add(beanPostProcessor);
                            continue;
                        }
                        
                        
                        

                    }
                    if(aClass.isAnnotationPresent(Controller.class)){

                        Controller declaredAnnotation1 = aClass.getDeclaredAnnotation(Controller.class);
                        classId = declaredAnnotation1.value();

                        if("".equals(classId)) {
                            classId = StringUtils.uncapitalize(className);//首字母小写类名作为beanId

                        }

                    }
                    if(aClass.isAnnotationPresent(Repository.class)){

                        Repository declaredAnnotation1 = aClass.getDeclaredAnnotation(Repository.class);
                        classId = declaredAnnotation1.value();

                        if("".equals(classId)) {
                            classId = StringUtils.uncapitalize(className);//首字母小写类名作为beanId

                        }

                    }
                    if(aClass.isAnnotationPresent(Service.class)){

                        Service declaredAnnotation1 = aClass.getDeclaredAnnotation(Service.class);
                        classId = declaredAnnotation1.value();

                        if("".equals(classId)) {
                            classId = StringUtils.uncapitalize(className);//首字母小写类名作为beanId

                        }

                    }
                    
                    
                    //单例模式 or 多例模式的确定
                    String scope="singleton";
                    if(aClass.isAnnotationPresent(Scope.class)){
                        String scope_value = aClass.getDeclaredAnnotation(Scope.class).value();
                        if(scope_value.equals("prototype")){
                            scope =scope_value;
                        }
                    }

                    BeanDefinition beanDefinition = new BeanDefinition();
                    beanDefinition.setScope(scope);
                    beanDefinition.setaClass(aClass);
                    beanDefinition.setBeanName(classId);
                    
                    BeanDefinitionMap.put(classId,beanDefinition);//将bean加载信息封装放入容器中
                }
                else{
                    System.out.println(aClass.getName()+ "不是一个 spring bean类" + aClass);
                }
            }

        }
    }

    /**
     * 根据类信息实例化对象
     * @param beanDefinition
     * @return
     */
    private Object createBean(BeanDefinition beanDefinition){
        //得到bean的类型
        Class clazz = beanDefinition.getaClass();
        String beanName = beanDefinition.getBeanName();
        try {
            //使用反射得到实例
            Object instance = clazz.getDeclaredConstructor().newInstance();
            
            //依赖注入
            for (Field declaredField : clazz.getDeclaredFields()) {
                if (declaredField.isAnnotationPresent(Autowired.class)) {
                    // 处理@Autowired 注解的属性 required, 很简单，自己完成
                    if(!declaredField.isAnnotationPresent(Autowired.class)) continue;
                    Object bean = getBean(declaredField.getName());
                    declaredField.setAccessible(true);//需要爆破
                    declaredField.set(instance,bean);
                }
            }


            //我们在Bean的初始化方法前，调用后置处理器的before方法
            for (BeanPostProcessor beanPostProcessor : beanPostProcessorList) {
                //在后置处理器的before方法，可以对容器的bean实例进行处理
                //然后返回处理后的bean实例, 相当于做一个前置处理
                Object current =
                        beanPostProcessor.postProcessBeforeInitialization(instance, beanName);
                if (current != null) {
                    instance = current;
                }
            }
            
            
            
            //bean初始化方法加载判断
            if(instance instanceof InitializingBean){
                try {
                    //执行bean的初始化方法
                    ((InitializingBean)instance).afterPropertiesSet();
                
                } catch (Exception e) {
                    e.printStackTrace();
                }
            }

            //我们在Bean的初始化方法后，调用后置处理器的after方法
            for (BeanPostProcessor beanPostProcessor : beanPostProcessorList) {
                //在后置处理器的after方法，可以对容器的bean实例进行处理
                //然后返回处理后的bean实例, 相当于做一个后置处理
                //原生Spring容器，比我们这个还要复杂
                Object current =
                        beanPostProcessor.postProcessAfterInitialization(instance, beanName);
                if(current != null) {
                    instance = current;
                }
            }
            
            
            return instance;
        } catch (InstantiationException e) {
            e.printStackTrace();
        } catch (IllegalAccessException e) {
            e.printStackTrace();
        } catch (InvocationTargetException e) {
            e.printStackTrace();
        } catch (NoSuchMethodException e) {
            e.printStackTrace();
        }
        //如果没有创建成功，返回null
        return null;
    }
    
}
